import * as util from '../core/util'
// 过滤规则
window.UEDITOR_CONFIG['filterTxtRules'] = (function () {
    var styles = ['text-align', 'line-height', 'text-indent'];

    function noop(node) {

    }

    // 粘贴时h和p标签只保留居中、缩进和行高的样式
    function removeStyle(node) {
        var arr = [];
        for (var i = 0, len = styles.length; i < len; i++) {
            arr.push(node.getStyle(styles[i]));
        }
        node.attrs.style = '';
        for (var i = 0, len = styles.length; i < len; i++) {
            if (arr[i]) {
                node.setStyle(styles[i], arr[i]);
            }
        }
    }

    return {
        //直接删除及其字节点内容
        '-': 'script style object iframe embed input select caption br',
        'p': removeStyle,
        'br': {$: {}},
        'div': {'$': {}},
        'caption': noop,
        'th': noop,
        'tr': noop,
        'table': function (node) { // 支持发布后保留边框的线
            if (!node.attrs['border']) node.attrs['border'] = '1';
            if (!node.attrs['rules']) node.attrs['rules'] = 'all';
        },
        'tbody': noop,
        'h1': removeStyle,
        'h2': removeStyle,
        'h3': removeStyle,
        'h4': removeStyle,
        'h5': removeStyle,
        'h6': removeStyle,
        'ol': noop,
        'ul': noop,
        'li': noop,
        'td': function (node) {
            removeStyle(node);
            // 移除p标签与编辑器产生的td一致
            UE.utils.each(node.getNodesByTagName('p'), function (p) {
                for (var i = 0; i < p.children.length; i++) {
                    node.appendChild(p.children[i]);
                    i--;
                }
                node.removeChild(p);
            });
            // 移除图片防止本地路径的图片
            UE.utils.each(node.getNodesByTagName('img'), function (img) {
                img.parentNode.removeChild(img);
            });
        },
        'sup': noop,
        'img': noop,
        'span': noop
    }
})();
// 注册段落样式
UE.plugin.register("fontstyle", function () {
    var e = this;
    return {
        commands: {
            fontstyle: {
                execCommand: function (t, n) {
                    // 从h标签改为p标签时只有不传第三个参数才能修改
                    if (n.tagName.toLowerCase() === 'p') {
                        e.execCommand("paragraph", n.tagName);
                    }
                    var domUtiles = UE.dom.domUtils;
                    n = $.extend(true, {}, n);
                    if (!n.style) {
                        // 防止标题切换时保留了原字体大小
                        var node = domUtiles.filterNodeList(e.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6');
                        if (node) {
                            domUtiles.setStyle(node, 'font-size', '');
                            n.style = node.getAttribute('style')
                        }
                    }
                    e.execCommand("paragraph", n.tagName, {
                        style: n.style
                    });
                },
                queryCommandValue: function (t) {
                    return e.queryCommandValue('paragraph');
                    //var node = UE.dom.domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6');
                    //return node ? {tagName: node.tagName.toLowerCase(), style: node.getAttribute('style').toLowerCase()}: {};
                }
            }
        }
    }
});
// 清除格式
UE.plugin.register("clearformat", function () {
    return {
        commands: {
            clearformat: {
                execCommand: function (t) {
                    this.execCommand('removeformat');
                    if (this.queryCommandState('subscript')) {
                        this.execCommand('subscript');
                    } else if (this.queryCommandState('superscript')) {
                        this.execCommand('superscript');
                    }
                }
            }
        }
    }
});
// 下划线和删除线
UE.plugin.register("ins&del", function () {

    var cmd = {ins: 'underline', del: 'strikethrough'},
        domUtils = UE.dom.domUtils,
        dtd = UE.dom.dtd,
        tagReg = /^(?:span|a)$/i,
        filter = function (node) {
            return node.nodeType == 1;
        };

    // 移除style中的特定值
    function removeStyleValue(range, style, value) {

        var bookmark1 = range.createBookmark(),
            parent;
        if (range.collapsed) {
            range.enlarge(true);
        }

        //不能把a标签切了
        var aNode = domUtils.findParentByTagName(range.startContainer, 'a', true);
        if (aNode) {
            range.setStartBefore(aNode);
        }

        aNode = domUtils.findParentByTagName(range.endContainer, 'a', true);
        if (aNode) {
            range.setEndAfter(aNode);
        }


        var bookmark = range.createBookmark();

        node = bookmark.start;

        //切开始
        while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
            domUtils.breakParent(node, parent);

            domUtils.clearEmptySibling(node);
        }
        if (bookmark.end) {
            //切结束
            node = bookmark.end;
            while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
                domUtils.breakParent(node, parent);
                domUtils.clearEmptySibling(node);
            }

            //开始去除样式
            var current = domUtils.getNextDomNode(bookmark.start, false, filter),
                styleValue,
                next;
            while (current) {
                if (current == bookmark.end) {
                    break;
                }

                next = domUtils.getNextDomNode(current, true, filter);

                if (!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(current)) {
                    if (tagReg.test(current.tagName) && (styleValue = domUtils.getStyle(current, style))) {
                        domUtils.setStyle(current, style, styleValue.replace(value, ''));
                    }
                }
                current = next;
            }
        }
        var pN = bookmark.start.parentNode;
        range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
        //清除冗余的代码 <b><bookmark></b>
        var node = range.startContainer,
            tmp,
            collapsed = range.collapsed;
        while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
            tmp = node.parentNode;
            range.setStartBefore(node);
            //trace:937
            //更新结束边界
            if (range.startContainer === range.endContainer) {
                range.endOffset--;
            }
            domUtils.remove(node);
            node = tmp;
        }

        if (!collapsed) {

            // 选区头不存在
            if (node.nodeType === 1 && !node.childNodes[range.startOffset]) {
                while (!node.nextSibling && dtd.$removeEmpty[node.tagName]) {
                    node = node.parentNode;
                }
                if (node.nextSibling) {
                    range.setStart(node.nextSibling, 0);
                }
            }

            node = range.endContainer;
            while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
                tmp = node.parentNode;
                range.setEndBefore(node);
                domUtils.remove(node);
                node = tmp;
            }
        }
    }

    function execCommand(cmdName) {
        var range = this.selection.getRange();
        // 如果有选区且选区头包含该cmdName样式则清除
        if (!range.collapsed && this.queryCommandState(cmd[cmdName])) {
            removeStyleValue(range, 'text-decoration', cmdName === 'ins' ? 'underline' : 'line-through');
            range.select();
        } else {
            this.execCommand(cmd[cmdName]);
        }
    }

    function queryCommandValue(cmdName) {
        return this.queryCommandValue(cmd[cmdName]);
    }

    function queryCommandState(cmdName) {
        return this.queryCommandState(cmd[cmdName]);
    }

    return {
        commands: {
            ins: {
                execCommand: execCommand,
                queryCommandValue: queryCommandValue,
                queryCommandState: queryCommandState
            },
            del: {
                execCommand: execCommand,
                queryCommandValue: queryCommandValue,
                queryCommandState: queryCommandState
            }
        }
    }
});

// 注册增加减小缩进
UE.plugin.register("indentchange", function () {
    var me = this;
    const pxRE = /px/g;
    function setTextIndent(type) {
        var range = me.selection.getRange(),
            startNode = getBodyChild(range.startContainer),
            endNode = getBodyChild(range.endContainer);
        var nodes = [];
        while (startNode) {
            if (['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].indexOf(startNode.tagName && startNode.tagName.toLowerCase()) > -1) {
                nodes.push(startNode);
            }
            if (startNode === endNode) {
                break;
            }
            startNode = startNode.nextSibling;
        }
        for (var i = 0, len = nodes.length; i < len; i++) {
            /**
             * modified by lyu on 2018/08/09
             * 缩进时，当前的缩进值可能是px单位
             * 换算成em之后再执行缩进操作
             */
            let curTextIndent = UE.dom.domUtils.getStyle(nodes[i], 'text-indent')
                , num = 0;
            if(pxRE.test(curTextIndent)){
                // 当前缩进为px单位，换算成em，默认编辑器body的fontSize是16px
                num = parseInt(parseInt(curTextIndent || 0) / 16);
            }else{
                // 当前是em
                num = parseInt(curTextIndent || 0);
            }
            let value;
            if (type === 'increase') {
                value = (num < 36 ? num + 2 : 36) + 'em';
            } else {
                // indent可能会小于0的bug
                value = num > 0 ? num - 2 : 0;
                value = (value < 0 ? 0 : value) + 'em';
            }
            UE.dom.domUtils.setStyle(nodes[i], 'text-indent', value);
        }
    }

    // function removeFillChar(rng) {
    //     var fillCharReg = new RegExp(UE.dom.domUtils.fillChar, 'g');
    //     if (rng.collapsed && rng.inFillChar()) {
    //         var child = rng.startContainer;
    //         if (UE.dom.domUtils.isFillChar(child)) {
    //             rng.setStartBefore(child).collapse(true);
    //         } else if (UE.dom.domUtils.isFillChar(child, true)) {
    //             child.nodeValue = child.nodeValue.replace(fillCharReg, '');
    //             rng.startOffset--;
    //             rng.collapsed && rng.collapse(true);
    //         }
    //     }
    // }
    function isFirstRng(rng) {
        var offset = rng.startOffset;
        if (!offset) return true;
        var start = rng.startContainer;
        if (start.nodeType === 3) {
            for (var i = 0; i < offset; i++) {
                if (start.nodeValue.charAt(i) !== UE.dom.domUtils.fillChar) return false;
            }
            return true;
        }
        return false;
    }

    function isFirstNode(parent, node) {
        return parent && (parent === node || isFirstNode(parent.childNodes[0], node));
    }

    function getParent(rng) {
        return UE.dom.domUtils.findParent(rng.startContainer, function (node) {
            return ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].indexOf(node.tagName && node.tagName.toLowerCase()) > -1
        }, true);
    }

    function getBodyChild(node) {
        return UE.dom.domUtils.findParent(node, function (node) {
            return node && node.parentNode && node.parentNode.tagName.toLowerCase() === 'body'
        }, true);
    }

    function isEmptyNode(node) {
        var domUtils = UE.dom.domUtils;
        return node && (!node.childNodes.length || !domUtils.getChildCount(node, function (node) {
            return !domUtils.isBr(node) && !domUtils.isFillChar(node)
        }))
    }

    me.addListener('delkeydown', function (type, evt) {
        var rng = me.selection.getRange(),
            parentNode = getParent(rng),
            num = me.queryCommandValue("indent");
        // removeFillChar(rng);
        if (rng.collapsed && isFirstRng(rng) && isFirstNode(parentNode, rng.startContainer) && num > 0) {
            me.execCommand('outdent');
            evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
            return true;
        }
        // 空节点时移除该节点，并设置光标于上行末尾
        // if (rng.collapsed && isFirstNode(parentNode, rng.startContainer) && isEmptyNode(parentNode) && !num) {
        //     rng.setStartAtLast(parentNode.previousSibling.lastChild).collapse(true).select();
        //     UE.dom.domUtils.remove(parentNode);
        //     evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
        //     return true;
        // }
    });
    me.addListener('tabkeydown', function (type, evt) {
        var rng = me.selection.getRange(),
            parentNode = getParent(rng);
        // removeFillChar(rng);
        if (rng.collapsed && isFirstRng(rng) && isFirstNode(parentNode, rng.startContainer)) {
            me.execCommand('upindent');
            evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
            return true;
        }
    });
    return {
        commands: {
            upindent: {
                execCommand: function () {
                    setTextIndent('increase');
                }
            },
            outdent: {
                execCommand: function () {
                    setTextIndent('decrease');
                }
            }
        }
    }
});
// 注册增大缩小字体
UE.plugin.register("fontsizechange", function () {
    var e = this,
        //t = [8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 26, 36, 48, 72];
        t = [6.7, 7.7, 8.7, 10, 12, 14, 16, 18.7, 20, 21.7, 24, 29.7, 32, 34.7, 48, 56];

    var fontSize = {
        h1: '32px',
        h2: '24px',
        h3: '20px',
        h4: '16px',
        h5: '14px',
        h6: '12px',
        p: '16px'
    };

    // 设置默认大小和字体
    function setDefaultFont(root) {
        UE.utils.each(root.getNodesByTagName('p h1 h2 h3 h4 h5 h6'), function (node) {
            node.setStyle('font-family', '微软雅黑');
            node.setStyle('font-size', fontSize[node.tagName.toLowerCase()]);
        });
    }

    // e.addInputRule(setDefaultFont);
    // e.addOutputRule(setDefaultFont);

    return {
        shortcutkey: {
            upsize: 'ctrl+187',
            downsize: 'ctrl+189'
        },
        commands: {
            upsize: {
                execCommand: function () {
                    for (var n = Number(e.queryCommandValue("fontsize").replace('px', '')), o = 0; o < t.length; o++)
                        if (t[o] > n) {
                            e.execCommand("fontsize", t[o] + "px");
                            break
                        }
                }
            },
            downsize: {
                execCommand: function () {
                    for (var n = Number(e.queryCommandValue("fontsize").replace('px', '')), o = t.length - 1; o >= 0; o--)
                        if (t[o] < n) {
                            e.execCommand("fontsize", t[o] + "px");
                            break
                        }
                }
            }
        }
    }
});

// 注册媒体
UE.plugin.register("insertmedia", function () {
    var no = 1; // 添加media的编号
    var e = this,
        generateString = (function () {
            var dealImage = function (info) {
                info.uuid = info.uuid || util.generateGuid();
                return addCenter('<img data_source="{0}" src="{1}" style="max-width:100%;" role="999"/>'.format(info.uuid, info.src), info.describe);
            };
            var dealVideo = function (info) {
                no++;
                info.uuid = info.uuid || util.generateGuid();
                return addCenter('<video preload="none" poster="'+globalVar.SITEORIGIN+'Editor/images/videoDefaultImg.jpg" style="width: 420px; height: 250px; max-width: 100%;" id="_insertVideo' + no + '"' +
                    'data_source="{0}" src="{1}" controls="controls" {2}></video>'.format(info.uuid, info.src, UE.browser.ie ? 'contenteditable="false"' : ''), info.describe);
            };
            var dealAudio = function (info) {
                info.uuid = info.uuid || util.generateGuid();
                return addCenter('<audio style="max-width:100%;" preload="none" data_source="{0}" src="{1}" controls="controls" {2}></audio>'.format(info.uuid, info.src, UE.browser.ie ? 'contenteditable="false"' : ''), info.describe);
            };
            var addCenter = function (str, describe) {
                // 设置居中
                str = '<p style="text-align:center" {0}>{1}</p>'.format(UE.browser.ie ? 'contenteditable="false"' : '', str);
                if (describe) {
                    // 添加描述并居中
                    str += '<p style="text-align:center">' + describe.htmlEscape() + '</p>';
                }
                return str;
            };
            return {
                image: dealImage,
                img: dealImage,
                video: dealVideo,
                audio: dealAudio
            }
        })();

    e.addInputRule(function (root) {
        UE.utils.each(root.getNodesByTagName('video audio'), function (node) {
            if (UE.browser.ie) {
                node.attrs && (node.attrs.contenteditable = "false");
                node.parentNode.tagName === 'p' && (node.parentNode.attrs.contenteditable = "false");
            } else {
                node.attrs && (node.attrs.contenteditable = "true");
                node.parentNode.tagName === 'p' && (node.parentNode.attrs.contenteditable = "true");
            }
        });
    });

    return {
        commands: {
            insertmedia: {
                execCommand: function (cmd, data) {
                    var fn = generateString[data.type];
                    if (fn) {
                        e.execCommand('insertHtml', fn(data));
                        e.autoAdjustHeight();
                    }
                }
            }
        }
    }
});

// 注册公式
UE.plugin.register("formula", function () {
    var e = this;

    // 将公式转换为图片在页面显示
    function drawCanvas(div, time, mathTag) {
        // 防止div内的数学公式标签还未被渲染为普通标签
        if (time > 100) {
            return;
        } else if (div.offsetWidth === 0) {
            setTimeout(function () {
                drawCanvas(div, time + 1, mathTag);
            }, 100);
        } else {
            // 将公式渲染完后生成的style标签加入到mathIframe里
            $('#mathIframe').contents().find('body').append(div);
            var mathIframe = $('#mathIframe').contents(),
                mathIframeStyles = mathIframe.find('style'),
                styles = $('style');
            if (mathIframeStyles.length !== styles.length) {
                mathIframe.find('head').html('');
                mathIframe.find('head').append(styles.clone());
            }
            // 将html标签转成canvas
            html2canvas(div, {
                onrendered: function (canvas) {
                    var data = canvas.toDataURL(),
                        describe = $.i18n('toolbar_formula');
                    $.ajax({
                        url: window.applicationPath + "/File/FormulaUpload",
                        type: "POST",
                        data: {fileContent: data.replace('data:image/png;base64,', '')},
                        dataType: 'json',
                        success: function (data) {
                            var str;
                            if (data && data.Code === 200) {
                                str = "<img data_source='" + util.generateGuid() + "' src='" + data.Data + "'  style='max-width:100%;' title='" + describe + "' data-math='" + escape(mathTag) + "'/>";
                                e.execCommand('insertHtml', str, true);
                                e.autoAdjustHeight();
                            }
                        },
                        error: function () {

                        }
                    });
                }
            });
        }
    }

    function addMathStyle() {
        // 防止公式末尾出现竖线
        var style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = '.MathJax nobr > span.math > span {border-left-width: 0 !important;}';
        document.head.appendChild(style);
    }

    // 创建一个iframe用于将html转化成canvas
    function createMathIframe() {
        var iframe = document.createElement('iframe');
        iframe.id = 'mathIframe';
        iframe.style.border = '0px';
        iframe.style.padding = '0px';
        iframe.style.width = '100%';
        iframe.style.height = '100%';
        iframe.style.position = 'fixed';
        iframe.style.zIndex = -1;
        document.body.appendChild(iframe);
        $(iframe).contents().find('head').append($('style').clone());
        iframe = null;
    }

    if (!document.getElementById('mathIframe')) {
        addMathStyle();
        createMathIframe();
    }

    e.ready(function () {
        $(e.iframe).contents().on('click', 'img', util.doubleClick(function () {
            var math = this.getAttribute('data-math');
            if (math) {
                e.math = unescape(math);
                e.getDialog('formula').open();
            }
        }));
    });

    return {
        commands: {
            formula: {
                execCommand: function (cmd, math) {
                    var html = math.replace('<math>', '<math xmlns="http://www.w3.org/1998/Math/MathML">'),
                        div = document.createElement('div');
                    div.id = 'tempDiv';
                    div.style.position = 'fixed';
                    // 设置透明
                    div.style.opacity = '0.0';
                    div.innerHTML = html;
                    $('body').append(div);
                    MathJax.Hub.Queue(["Typeset", MathJax.Hub, div]);
                    // 绘制canvas
                    drawCanvas(div, 1, math);
                }
            }
        }
    }
});

// 重写ueditor.all.js的插入表格方法
UE.commands.inserttable.execCommand = function insertTable(cmd, opt) {
    // 创建表
    function createTable(opt, tdWidth, tableWidth) {
        var html = [],
            rowsNum = opt.numRows,
            colsNum = opt.numCols;
        if (opt.describe) {
            html.push("<caption>" + opt.describe + "</caption>");
        }
        for (var r = 0; r < rowsNum; r++) {
            html.push('<tr' + (r == 0 ? ' class="firstRow"' : '') + '>');
            for (var c = 0; c < colsNum; c++) {
                if (tdWidth) {
                    html.push('<td width="' + tdWidth + '" vAlign="top" align="left">' + (UE.browser.ie && UE.browser.version < 11 ? UE.dom.domUtils.fillChar : '<br/>') + '</td>');
                } else {
                    html.push('<td vAlign="top" align="left">' + (UE.browser.ie && UE.browser.version < 11 ? UE.dom.domUtils.fillChar : '<br/>') + '</td>');
                }
            }
            html.push('</tr>');
        }
        var uuid = util.generateGuid();
        // return '<table rules="all" border="1" align="center" width="' + tableWidth + '" data_source="' + uuid + '" style="max-width: 100%;"><tbody>' + html.join('') + '</tbody></table>';
        return '<table rules="all" border="1" align="center" data_source="' + uuid + '" style="max-width: 100%;"><tbody>' + html.join('') + '</tbody></table>';
    }

    if (!opt) {
        opt = UE.utils.extend({}, {
            numCols: this.options.defaultCols,
            numRows: this.options.defaultRows,
            tdvalign: this.options.tdvalign
        })
    }
    var me = this;
    var range = this.selection.getRange(),
        start = range.startContainer,
        firstParentBlock = UE.dom.domUtils.findParent(start, function (node) {
            return UE.dom.domUtils.isBlockElm(node);
        }, true) || me.body;
    var defaultValue = UE.UETable.getDefaultValue(me),
        tableWidth = firstParentBlock.offsetWidth,
        tdWidth = Math.floor(tableWidth / opt.numCols - defaultValue.tdPadding * 2 - defaultValue.tdBorder);
    tableWidth = tableWidth - (defaultValue.tableBorder || 1) * 2;

    !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);

    // 添加表格后添加一行
    var p = me.document.createElement("p"),
        autotypeset = me.getOpt('autotypeset');
    p.innerHTML = UE.browser.ie ? '&nbsp;' : '<br />';
    //if (autotypeset.indent) {
    //    p.style.textIndent = autotypeset.indentValue;
    //}

    me.execCommand("inserthtml", createTable(opt, tdWidth, tableWidth) + p.outerHTML);
    // 修改为按文字调整
    //me.execCommand("inserthtml", createTable(opt) + p.outerHTML);
};


// 调整表格属性
UE.plugin.register("tableattr", function () {
    function setDefaultFont(root) {
        UE.utils.each(root.getNodesByTagName('td'), function (node) {
            node.attrs.valign = node.attrs.valign || 'top';
            node.attrs.align = node.attrs.align || 'left';
        });
    }

    var e = this;
    e.addInputRule(setDefaultFont);
    e.addOutputRule(setDefaultFont);
});

// 设置表格光标调整
UE.plugin.register("tablecursor", function () {
    var e = this;

    function getCellInfo(cell) {
        if (!cell) return;
        var cellIndex = cell.cellIndex,
            rowIndex = cell.parentNode.rowIndex,
            rowInfo = this.indexTable[rowIndex],
            numCols = this.colsNum;
        for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
            var cellInfo = rowInfo[colIndex];
            if (cellInfo.rowIndex === rowIndex && cellInfo.cellIndex === cellIndex) {
                return {
                    rowIndex: rowIndex,
                    colIndex: colIndex
                };
            }
        }
    }

    function getPrevCell(ut, cellInfo) {
        var node,
            prevInfo;
        if (cellInfo.rowIndex) {
            prevInfo = ut.indexTable[cellInfo.rowIndex - 1][cellInfo.colIndex];
            node = ut.getCell(prevInfo.rowIndex, prevInfo.cellIndex);
        }
        return node;
    }

    function getNextCell(ut, cellInfo) {
        var node,
            nextInfo;
        while (cellInfo.rowIndex < ut.indexTable.length - 1 && util.equals(ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex], ut.indexTable[cellInfo.rowIndex + 1][cellInfo.colIndex])) {
            cellInfo.rowIndex++;
        }
        if (cellInfo.rowIndex < ut.indexTable.length - 1) {
            nextInfo = ut.indexTable[cellInfo.rowIndex + 1][cellInfo.colIndex];
            node = ut.getCell(nextInfo.rowIndex, nextInfo.cellIndex);
        }
        return node;
    }

    e.addListener('keydown', function (type, evt) {
        var keyCode = evt.keyCode || evt.which,
            range = e.selection.getRange(),
            tableRng = UE.UETable.getTableItemsByRange(e),
            node;
        if (!tableRng.table || !tableRng.tr || !tableRng.cell) return;
        var ut = UE.UETable.getUETable(tableRng.table),
            cellInfo = getCellInfo.call(ut, tableRng.cell);
        if (keyCode === 38) {// 上
            node = getPrevCell(ut, cellInfo) || tableRng.caption || tableRng.table.previousSibling;
        } else if (keyCode === 40) {// 下
            node = getNextCell(ut, cellInfo) || tableRng.table.nextSibling;
        }
        if (node) {
            while (node.nodeType !== 3 && node.tagName.toLowerCase() !== 'br') {
                node = node.lastChild;
            }
            if (node.nodeType !== 3 && node.tagName.toLowerCase() === 'br') {
                if (!node.previousSibling) {
                    node.parentNode.insertBefore(document.createTextNode(''), node);
                }
                node = node.previousSibling;
            }
            range.selectNode(node).collapse().select();
            evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
        }
    });
});

// 重写表格合并代码
UE.UETable.prototype.mergeRange = function () {
    //由于合并操作可以在任意时刻进行，所以无法通过鼠标位置等信息实时生成range，只能通过缓存实例中的cellsRange对象来访问
    var range = this.cellsRange,
        leftTopCell = this.getCell(
            range.beginRowIndex,
            this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
        );

    // 这段关于行表头或者列表头的特殊处理会导致表头合并范围错误
    // 为什么有这段代码的原因未明，暂且注释掉，希望原作者看到后出面说明下
    // if (
    //   leftTopCell.tagName == "TH" &&
    //   range.endRowIndex !== range.beginRowIndex
    // ) {
    //   var index = this.indexTable,
    //     info = this.getCellInfo(leftTopCell);
    //   leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
    //   range = this.getCellsRange(
    //     leftTopCell,
    //     this.getCell(
    //       index[this.rowsNum - 1][info.colIndex].rowIndex,
    //       index[this.rowsNum - 1][info.colIndex].cellIndex
    //     )
    //   );
    // }

    // 删除剩余的Cells
    var cells = this.getCells(range);
    for (var i = 0, ci; (ci = cells[i++]);) {
        if (ci !== leftTopCell) {
            this.moveContent(leftTopCell, ci);
            this.deleteCell(ci);
        }
    }
    // 修改左上角Cell的rowSpan和colSpan，并调整宽度属性设置
    leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
    // leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
    leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
    // leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
    // if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
    //   leftTopCell.colSpan = 1;
    // }

    // if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
    //   var rowIndex = leftTopCell.parentNode.rowIndex;
    //   //解决IE下的表格操作问题
    //   if (this.table.deleteRow) {
    //     for (
    //       var i = rowIndex + 1,
    //         curIndex = rowIndex + 1,
    //         len = leftTopCell.rowSpan;
    //       i < len;
    //       i++
    //     ) {
    //       this.table.deleteRow(curIndex);
    //     }
    //   } else {
    //     for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
    //       var row = this.table.rows[rowIndex + 1];
    //       row.parentNode.removeChild(row);
    //     }
    //   }
    //   leftTopCell.rowSpan = 1;
    // }
    this.update();
}

// 设置图片等资源加载后调整高度
UE.plugin.register("autoadjustheight", function () {
    var e = this,
        obj = {
            img: 'onload',
            video: 'ondurationchange',
            audio: 'ondurationchange'
        };

    function loadEvent() {
        e.fireEvent('afterinserthtml');
        if (this.tagName.toLowerCase() === 'img') {
            // 设置默认的宽高以便转换后出现问题
            !this.getAttribute('width') && this.setAttribute('width', this.offsetWidth);
            !this.getAttribute('height') && this.setAttribute('height', this.offsetHeight);
        }
        e.fireEvent('contentchange');
    }

    e.autoAdjustHeight = function () {
        for (var key in obj) {
            var array = UE.dom.domUtils.getElementsByTagName(e.document, key);
            UE.utils.each(array, function (item) {
                if (!item[obj[key]]) {
                    item[obj[key]] = loadEvent;
                }
            });
            array = null;
        }
    };
    return {
        commands: {
            autoadjustheight: {
                execCommand: e.autoAdjustHeight
            }
        }
    }
});

// 插入引用
UE.plugin.register("insertQuote", function () {
    var me = this,
        lastSupList = [];

    function openDialog(type, _this) {
        if(type === "selfTrigger"){
            me.quoteTag = _this;
        } else {
            me.quoteTag = this;
        }
        me.getDialog('quote').open();
    }

    me.addListener('contentchange quoteChange', function () {
        util.Observer.fire('quoteChange');
        util.Observer.fire('contentchange', me);
    });

    me.ready(function () {
        new UE.ui['quote'](me);
        $(me.document.body).on('click', 'sup[contenteditable]', openDialog);
    });

    function isQuoteNode(node) {
        return node && node.nodeType !== 3 && node.tagName.toLowerCase() === 'sup' && node.getAttribute('contenteditable') === "false";
    }

    function isEmptyNode(node) {
        return node && node.nodeType === 3 && (!node.data || node.data === UE.dom.domUtils.fillChar);
    }

    // 判断光标是否在段落头
    function isInHead(rng) {
        var node = rng.startContainer,
            index = rng.startOffset;
        if (node.nodeType === 3) {
            if (index !== 0 && node.data !== UE.dom.domUtils.fillChar) return false;
        } else if (index > 0) {
            if (node.childNodes[index]) node = node.childNodes[index];
            else return false;
        }
        while (node.nodeType === 3 || node.tagName.toLowerCase() !== 'p') {
            if (node.previousSibling) {
                if (!UE.dom.domUtils.isEmptyNode(node.previousSibling)) return false;
                node = node.previousSibling;
            } else {
                node = node.parentNode;
            }
        }
        return true;
    }

    // 兼容火狐下删不掉引用
    me.addListener('delkeydown', function (type, evt) {
        var rng = me.selection.getRange(),
            node = rng.startContainer,
            fillCharReg = new RegExp(UE.dom.domUtils.fillChar, 'g');
        if (!rng.collapsed) return;
        if (node.nodeType === 3) {
            if ((rng.startOffset === 0 || rng.startOffset === 1 && fillCharReg.test(node.data.charAt(0))) && isQuoteNode(node.previousSibling)) {
                node.previousSibling.remove ? node.previousSibling.remove() : node.previousSibling.removeNode(true);
                evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
                return true;
            } else if (node.parentNode.tagName.toLowerCase() === 'sup' && node.parentNode.getAttribute('data-quote')) {
                node.parentNode.remove ? node.parentNode.remove() : node.parentNode.removeNode(true);
                evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
                return true;
            }
        } else {
            var index = rng.startOffset - 1;
            if (rng.startOffset > 0 && (isQuoteNode(node.childNodes[index]) || (isEmptyNode(node.childNodes[index]) && isQuoteNode(node.childNodes[--index])))) {
                node.childNodes[index].remove ? node.childNodes[index].remove() : node.childNodes[index].removeNode(true);
                evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
                return true;
            }
        }
    });

    // 删行时将引用信息返回上一行
    // 浏览器默认行为会把contenteditable为false的删除，所以临时将其置于true
    me.addListener('delkeydown', function (type, evt) {
        var rng = me.selection.getRange(),
            domUtils = UE.dom.domUtils,
            node;
        if (rng.collapsed && isInHead(rng)) {
            node = rng.startContainer;
        } else if (!rng.collapsed && domUtils.findParentByTagName(rng.startContainer, 'p', true) !== domUtils.findParentByTagName(rng.endContainer, 'p', true)) {
            node = rng.endContainer;
        }
        while (node && (node.nodeType !== 1 || node.tagName.toLowerCase() !== 'body')) {
            if (node.nodeType !== 3) {
                domUtils.getElementsByTagName(node, 'sup', function (sup) {
                    if (sup.hasAttribute('contenteditable')) {
                        sup.setAttribute('contenteditable', true);
                    }
                });
                if (node.tagName.toLowerCase() === 'sup' && node.hasAttribute('contenteditable')) {
                    node.setAttribute('contenteditable', true);
                }
            }
            node = node.nextSibling || node.parentNode;
        }
    });

    return {
        commands: {
            insertquote: {
                execCommand: function (cmd, data) {
                    var range = me.selection.getRange().collapse(),
                        curNode = range.startContainer,
                        obj = UE.dom.domUtils.filterNodeList(me.selection.getStartElementPath(), 'sup');

                    var tempNode = range.document.createElement('sup');
                    var text = range.document.createTextNode(UE.dom.domUtils.fillChar);
                    tempNode.setAttribute('contenteditable', false);
                    tempNode.setAttribute('class', 'data-quote-insert')
                    tempNode.setAttribute('data-quote', data && data.quote || '');
                    if (data && data.info) {
                        if (data.info.Title) data.info.Title = data.info.Title.replace(/<span.*?>(.*?)<\/span>/g, '$1');
                        if (data.info.title) data.info.title = data.info.title.replace(/<span.*?>(.*?)<\/span>/g, '$1');
                        tempNode.setAttribute('data-info', escape(JSON.stringify(data.info)));
                    }
                    tempNode.innerHTML = '[1]';
                    if (obj) {
                        obj.parentNode.insertBefore(tempNode, obj.nextSibling);
                        range.setStartBefore(tempNode).collapse();
                    } else {
                        range.insertNode(tempNode);
                        tempNode.parentNode.insertBefore(text, tempNode.nextSibling);
                        range.setEndAfter(text).setStartAfter(text).collapse().select();
                        setTimeout(() => {
                            openDialog("selfTrigger", tempNode);
                            // $(tempNode).click();
                        }, 0);
                    }
                    me.fireEvent('contentchange');
                }
            }
        }
    }
});

// 注册保存快捷键
UE.plugin.register("saveAndSubmit", function () {

    return {
        shortcutkey: {
            savecontent: 'ctrl+83',
        },
        commands: {
            savecontent: {
                execCommand: function (cmd) {
                    Observer.fire('saveContent', this);
                }
            }
        }
    }
});

// 注册右键删除功能
UE.plugin.register("deleteobject", function () {
    var me = this
        , domUtils = UE.dom.domUtils;

    return {
        commands: {
            deleteobject: {
                execCommand: function (cmd, data) {
                    var target = data.target.parentNode || data.target.parentElement;
                    domUtils.remove(target);
                }
            }
        }
    }
})
